Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-266.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 1.233.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
1189 3351 5405 6931 1559 5680 2577 4731 3394 1660 5048 2775 2457 1521  434 8127 
  17   18   19   20   21   22   23   24   25 
8222 4407 4336 2678 3271 3615 5172 5067 1274 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
      fecha_cnt       tmax       tmin      precip  longitud   latitud
[1,] -0.1111283 -0.8501678 -0.8647276 0.459720660 0.5454643 0.2517221
[2,]  0.7112933  0.3337954  0.2488274 0.008731722 0.3323687 0.2300587
        altitud
[1,] 0.34643126
[2,] 0.07716693

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
 longitud      tmax   altitud   latitud      tmin fecha_cnt    precip 
0.9444710 0.9225596 0.9203733 0.9171422 0.9115675 0.9050848 0.8515693 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.000   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.502   Mean   :217.4   Mean   :150.6   Mean   :  6.925   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03086   Mean   :28.36   Mean   :-16.05   Mean   : 518.7  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.0   1st Qu.:  49.00   1st Qu.:  3.00  
 Median : 6.000   Median :196.0   Median :  94.00   Median : 10.00  
 Mean   : 6.498   Mean   :200.7   Mean   :  95.27   Mean   : 14.23  
 3rd Qu.: 9.000   3rd Qu.:258.0   3rd Qu.: 143.00   3rd Qu.: 21.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :126.00  
     nevada           prof_nieve           longitud        latitud       
 Min.   :0.000000   Min.   :   0.0000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:38.95   1st Qu.:-4.8458  
 Median :0.000000   Median :   0.0000   Median :40.95   Median :-2.4831  
 Mean   :0.000332   Mean   :   0.5073   Mean   :40.50   Mean   :-2.3476  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.: 0.5706  
 Max.   :6.000000   Max.   :1834.0000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 261.0  
 Mean   : 420.3  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   : 46.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:128.0   1st Qu.: 59.00   1st Qu.: 61.50   1st Qu.:0  
 Median : 5.000   Median :151.0   Median : 81.00   Median : 73.00   Median :0  
 Mean   : 6.462   Mean   :156.7   Mean   : 84.23   Mean   : 81.14   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:182.0   3rd Qu.:108.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:41.42   1st Qu.: -8.411   1st Qu.:  27.0  
 Median :  0.0000   Median :42.89   Median : -5.598   Median :  95.0  
 Mean   :  0.3546   Mean   :41.67   Mean   : -4.854   Mean   : 186.9  
 3rd Qu.:  0.0000   3rd Qu.:43.36   3rd Qu.: -2.039   3rd Qu.: 261.0  
 Max.   :607.0000   Max.   :43.57   Max.   :  4.216   Max.   :2400.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.000   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.502   Mean   :217.4   Mean   :150.6   Mean   :  6.925   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03086   Mean   :28.36   Mean   :-16.05   Mean   : 518.7  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip     
 Min.   : 1.000   Min.   : -4.0   Min.   :-110.00   Min.   : 0.00  
 1st Qu.: 4.000   1st Qu.:152.0   1st Qu.:  52.00   1st Qu.: 3.00  
 Median : 6.000   Median :200.0   Median :  97.00   Median :10.00  
 Mean   : 6.495   Mean   :204.5   Mean   :  97.96   Mean   :13.55  
 3rd Qu.: 9.000   3rd Qu.:260.0   3rd Qu.: 145.00   3rd Qu.:20.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :84.00  
     nevada           prof_nieve        longitud        latitud       
 Min.   :0.000000   Min.   :  0.00   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.000000   1st Qu.:  0.00   1st Qu.:38.95   1st Qu.:-4.8500  
 Median :0.000000   Median :  0.00   Median :40.95   Median :-2.4831  
 Mean   :0.000343   Mean   :  0.06   Mean   :40.45   Mean   :-2.4210  
 3rd Qu.:0.000000   3rd Qu.:  0.00   3rd Qu.:42.01   3rd Qu.: 0.4914  
 Max.   :6.000000   Max.   :229.00   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 247.0  
 Mean   : 361.7  
 3rd Qu.: 639.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 31.00   1st Qu.: -30.00   1st Qu.: 17.00  
 Median : 7.000   Median : 82.00   Median :  15.00   Median : 30.00  
 Mean   : 6.588   Mean   : 89.27   Mean   :  17.83   Mean   : 33.66  
 3rd Qu.: 9.000   3rd Qu.:144.00   3rd Qu.:  68.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :255.00   Max.   : 150.00   Max.   :126.00  
     nevada    prof_nieve         longitud        latitud           altitud    
 Min.   :0   Min.   :   0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1213  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.00   Median :42.38   Median : 0.9844   Median :2143  
 Mean   :0   Mean   :  13.38   Mean   :41.95   Mean   :-0.2329   Mean   :2107  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   : 46.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:128.0   1st Qu.: 59.00   1st Qu.: 61.50   1st Qu.:0  
 Median : 5.000   Median :151.0   Median : 81.00   Median : 73.00   Median :0  
 Mean   : 6.462   Mean   :156.7   Mean   : 84.23   Mean   : 81.14   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:182.0   3rd Qu.:108.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:41.42   1st Qu.: -8.411   1st Qu.:  27.0  
 Median :  0.0000   Median :42.89   Median : -5.598   Median :  95.0  
 Mean   :  0.3546   Mean   :41.67   Mean   : -4.854   Mean   : 186.9  
 3rd Qu.:  0.0000   3rd Qu.:43.36   3rd Qu.: -2.039   3rd Qu.: 261.0  
 Max.   :607.0000   Max.   :43.57   Max.   :  4.216   Max.   :2400.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.000   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.502   Mean   :217.4   Mean   :150.6   Mean   :  6.925   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03086   Mean   :28.36   Mean   :-16.05   Mean   : 518.7  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip     
 Min.   :1.000   Min.   : -4.0   Min.   :-89.00   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:128.0   1st Qu.: 27.00   1st Qu.: 4.00  
 Median :3.000   Median :160.0   Median : 64.00   Median :11.00  
 Mean   :2.846   Mean   :161.8   Mean   : 62.93   Mean   :14.66  
 3rd Qu.:4.000   3rd Qu.:194.0   3rd Qu.: 96.00   3rd Qu.:22.00  
 Max.   :9.000   Max.   :321.0   Max.   :199.00   Max.   :80.00  
     nevada           prof_nieve          longitud        latitud      
 Min.   :0.000000   Min.   :  0.0000   Min.   :35.28   Min.   :-8.649  
 1st Qu.:0.000000   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.:-5.346  
 Median :0.000000   Median :  0.0000   Median :40.87   Median :-2.138  
 Mean   :0.000659   Mean   :  0.1254   Mean   :40.28   Mean   :-2.222  
 3rd Qu.:0.000000   3rd Qu.:  0.0000   3rd Qu.:41.98   3rd Qu.: 0.595  
 Max.   :6.000000   Max.   :229.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  34.0  
 Median : 127.0  
 Mean   : 304.4  
 3rd Qu.: 540.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 31.00   1st Qu.: -30.00   1st Qu.: 17.00  
 Median : 7.000   Median : 82.00   Median :  15.00   Median : 30.00  
 Mean   : 6.588   Mean   : 89.27   Mean   :  17.83   Mean   : 33.66  
 3rd Qu.: 9.000   3rd Qu.:144.00   3rd Qu.:  68.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :255.00   Max.   : 150.00   Max.   :126.00  
     nevada    prof_nieve         longitud        latitud           altitud    
 Min.   :0   Min.   :   0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1213  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.00   Median :42.38   Median : 0.9844   Median :2143  
 Mean   :0   Mean   :  13.38   Mean   :41.95   Mean   :-0.2329   Mean   :2107  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   : 46.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:128.0   1st Qu.: 59.00   1st Qu.: 61.50   1st Qu.:0  
 Median : 5.000   Median :151.0   Median : 81.00   Median : 73.00   Median :0  
 Mean   : 6.462   Mean   :156.7   Mean   : 84.23   Mean   : 81.14   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:182.0   3rd Qu.:108.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:41.42   1st Qu.: -8.411   1st Qu.:  27.0  
 Median :  0.0000   Median :42.89   Median : -5.598   Median :  95.0  
 Mean   :  0.3546   Mean   :41.67   Mean   : -4.854   Mean   : 186.9  
 3rd Qu.:  0.0000   3rd Qu.:43.36   3rd Qu.: -2.039   3rd Qu.: 261.0  
 Max.   :607.0000   Max.   :43.57   Max.   :  4.216   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   :  8.0   Min.   :-110.0   Min.   : 0.00  
 1st Qu.: 7.000   1st Qu.:177.0   1st Qu.:  73.0   1st Qu.: 2.00  
 Median : 9.000   Median :233.0   Median : 122.0   Median : 9.00  
 Mean   : 8.491   Mean   :227.9   Mean   : 117.1   Mean   :12.95  
 3rd Qu.:10.000   3rd Qu.:283.0   3rd Qu.: 162.0   3rd Qu.:19.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :84.00  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.0000000   1st Qu.: 0.00000   1st Qu.:38.99   1st Qu.:-4.8458  
 Median :0.0000000   Median : 0.00000   Median :40.95   Median :-2.9056  
 Mean   :0.0001707   Mean   : 0.02422   Mean   :40.54   Mean   :-2.5300  
 3rd Qu.:0.0000000   3rd Qu.: 0.00000   3rd Qu.:42.07   3rd Qu.: 0.4731  
 Max.   :3.0000000   Max.   :77.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  53.0  
 Median : 353.0  
 Mean   : 393.1  
 3rd Qu.: 667.0  
 Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94.0   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :129.0   Median : 51.00   Median :  3.00   Median :0  
 Mean   : 6.585   Mean   :138.4   Mean   : 60.83   Mean   : 10.29   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183.0   3rd Qu.: 98.00   3rd Qu.: 13.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253.0   Max.   :159.00   Max.   :114.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1766   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip     
 Min.   :1.000   Min.   : -4.0   Min.   :-89.00   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:128.0   1st Qu.: 27.00   1st Qu.: 4.00  
 Median :3.000   Median :160.0   Median : 64.00   Median :11.00  
 Mean   :2.846   Mean   :161.8   Mean   : 62.93   Mean   :14.66  
 3rd Qu.:4.000   3rd Qu.:194.0   3rd Qu.: 96.00   3rd Qu.:22.00  
 Max.   :9.000   Max.   :321.0   Max.   :199.00   Max.   :80.00  
     nevada           prof_nieve          longitud        latitud      
 Min.   :0.000000   Min.   :  0.0000   Min.   :35.28   Min.   :-8.649  
 1st Qu.:0.000000   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.:-5.346  
 Median :0.000000   Median :  0.0000   Median :40.87   Median :-2.138  
 Mean   :0.000659   Mean   :  0.1254   Mean   :40.28   Mean   :-2.222  
 3rd Qu.:0.000000   3rd Qu.:  0.0000   3rd Qu.:41.98   3rd Qu.: 0.595  
 Max.   :6.000000   Max.   :229.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  34.0  
 Median : 127.0  
 Mean   : 304.4  
 3rd Qu.: 540.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 31.00   1st Qu.: -30.00   1st Qu.: 17.00  
 Median : 7.000   Median : 82.00   Median :  15.00   Median : 30.00  
 Mean   : 6.588   Mean   : 89.27   Mean   :  17.83   Mean   : 33.66  
 3rd Qu.: 9.000   3rd Qu.:144.00   3rd Qu.:  68.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :255.00   Max.   : 150.00   Max.   :126.00  
     nevada    prof_nieve         longitud        latitud           altitud    
 Min.   :0   Min.   :   0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1213  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.00   Median :42.38   Median : 0.9844   Median :2143  
 Mean   :0   Mean   :  13.38   Mean   :41.95   Mean   :-0.2329   Mean   :2107  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax          tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87   Min.   : 64.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:212   1st Qu.:150.0   1st Qu.:  0.00   1st Qu.:0  
 Median : 6.000   Median :233   Median :168.0   Median :  1.00   Median :0  
 Mean   : 6.484   Mean   :234   Mean   :169.4   Mean   :  6.22   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:259   3rd Qu.:196.0   3rd Qu.:  7.00   3rd Qu.:0  
 Max.   :12.000   Max.   :356   Max.   :244.0   Max.   :102.00   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003521   Mean   :28.38   Mean   :-15.95   Mean   :130.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   : 46.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:128.0   1st Qu.: 59.00   1st Qu.: 61.50   1st Qu.:0  
 Median : 5.000   Median :151.0   Median : 81.00   Median : 73.00   Median :0  
 Mean   : 6.462   Mean   :156.7   Mean   : 84.23   Mean   : 81.14   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:182.0   3rd Qu.:108.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:41.42   1st Qu.: -8.411   1st Qu.:  27.0  
 Median :  0.0000   Median :42.89   Median : -5.598   Median :  95.0  
 Mean   :  0.3546   Mean   :41.67   Mean   : -4.854   Mean   : 186.9  
 3rd Qu.:  0.0000   3rd Qu.:43.36   3rd Qu.: -2.039   3rd Qu.: 261.0  
 Max.   :607.0000   Max.   :43.57   Max.   :  4.216   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   :  8.0   Min.   :-110.0   Min.   : 0.00  
 1st Qu.: 7.000   1st Qu.:177.0   1st Qu.:  73.0   1st Qu.: 2.00  
 Median : 9.000   Median :233.0   Median : 122.0   Median : 9.00  
 Mean   : 8.491   Mean   :227.9   Mean   : 117.1   Mean   :12.95  
 3rd Qu.:10.000   3rd Qu.:283.0   3rd Qu.: 162.0   3rd Qu.:19.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :84.00  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.0000000   1st Qu.: 0.00000   1st Qu.:38.99   1st Qu.:-4.8458  
 Median :0.0000000   Median : 0.00000   Median :40.95   Median :-2.9056  
 Mean   :0.0001707   Mean   : 0.02422   Mean   :40.54   Mean   :-2.5300  
 3rd Qu.:0.0000000   3rd Qu.: 0.00000   3rd Qu.:42.07   3rd Qu.: 0.4731  
 Max.   :3.0000000   Max.   :77.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  53.0  
 Median : 353.0  
 Mean   : 393.1  
 3rd Qu.: 667.0  
 Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94.0   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :129.0   Median : 51.00   Median :  3.00   Median :0  
 Mean   : 6.585   Mean   :138.4   Mean   : 60.83   Mean   : 10.29   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183.0   3rd Qu.: 98.00   3rd Qu.: 13.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253.0   Max.   :159.00   Max.   :114.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1766   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip     
 Min.   :1.000   Min.   : -4.0   Min.   :-89.00   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:128.0   1st Qu.: 27.00   1st Qu.: 4.00  
 Median :3.000   Median :160.0   Median : 64.00   Median :11.00  
 Mean   :2.846   Mean   :161.8   Mean   : 62.93   Mean   :14.66  
 3rd Qu.:4.000   3rd Qu.:194.0   3rd Qu.: 96.00   3rd Qu.:22.00  
 Max.   :9.000   Max.   :321.0   Max.   :199.00   Max.   :80.00  
     nevada           prof_nieve          longitud        latitud      
 Min.   :0.000000   Min.   :  0.0000   Min.   :35.28   Min.   :-8.649  
 1st Qu.:0.000000   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.:-5.346  
 Median :0.000000   Median :  0.0000   Median :40.87   Median :-2.138  
 Mean   :0.000659   Mean   :  0.1254   Mean   :40.28   Mean   :-2.222  
 3rd Qu.:0.000000   3rd Qu.:  0.0000   3rd Qu.:41.98   3rd Qu.: 0.595  
 Max.   :6.000000   Max.   :229.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  34.0  
 Median : 127.0  
 Mean   : 304.4  
 3rd Qu.: 540.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 31.00   1st Qu.: -30.00   1st Qu.: 17.00  
 Median : 7.000   Median : 82.00   Median :  15.00   Median : 30.00  
 Mean   : 6.588   Mean   : 89.27   Mean   :  17.83   Mean   : 33.66  
 3rd Qu.: 9.000   3rd Qu.:144.00   3rd Qu.:  68.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :255.00   Max.   : 150.00   Max.   :126.00  
     nevada    prof_nieve         longitud        latitud           altitud    
 Min.   :0   Min.   :   0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1213  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.00   Median :42.38   Median : 0.9844   Median :2143  
 Mean   :0   Mean   :  13.38   Mean   :41.95   Mean   :-0.2329   Mean   :2107  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax          tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87   Min.   : 64.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:212   1st Qu.:150.0   1st Qu.:  0.00   1st Qu.:0  
 Median : 6.000   Median :233   Median :168.0   Median :  1.00   Median :0  
 Mean   : 6.484   Mean   :234   Mean   :169.4   Mean   :  6.22   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:259   3rd Qu.:196.0   3rd Qu.:  7.00   3rd Qu.:0  
 Max.   :12.000   Max.   :356   Max.   :244.0   Max.   :102.00   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003521   Mean   :28.38   Mean   :-15.95   Mean   :130.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 56.0   Min.   :-22.00   Min.   : 46.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:129.0   1st Qu.: 60.00   1st Qu.: 60.00   1st Qu.:0  
 Median : 5.000   Median :154.0   Median : 81.00   Median : 70.00   Median :0  
 Mean   : 6.313   Mean   :158.7   Mean   : 85.32   Mean   : 72.55   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:184.0   3rd Qu.:109.00   3rd Qu.: 83.00   3rd Qu.:0  
 Max.   :12.000   Max.   :336.0   Max.   :219.00   Max.   :119.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :28.48   Min.   :-17.755   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:41.38   1st Qu.: -8.372   1st Qu.:  27.0  
 Median : 0.00000   Median :42.89   Median : -5.346   Median :  87.0  
 Mean   : 0.08425   Mean   :41.70   Mean   : -4.681   Mean   : 159.5  
 3rd Qu.: 0.00000   3rd Qu.:43.36   3rd Qu.: -2.039   3rd Qu.: 251.0  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.216   Max.   :1405.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip          nevada 
 Min.   : 1.00   Min.   :122.0   Min.   :-31.0   Min.   : 0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:221.0   1st Qu.:107.0   1st Qu.: 2.00   1st Qu.:0  
 Median : 7.00   Median :263.0   Median :144.0   Median : 8.00   Median :0  
 Mean   : 7.39   Mean   :258.3   Mean   :139.3   Mean   :11.16   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:296.0   3rd Qu.:175.0   3rd Qu.:17.00   3rd Qu.:0  
 Max.   :12.00   Max.   :403.0   Max.   :254.0   Max.   :84.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.47   1st Qu.:-4.7667   1st Qu.:  58.0  
 Median : 0.00000   Median :40.95   Median :-2.9056   Median : 405.0  
 Mean   : 0.00784   Mean   :40.60   Mean   :-2.5361   Mean   : 408.9  
 3rd Qu.: 0.00000   3rd Qu.:42.08   3rd Qu.: 0.3664   3rd Qu.: 685.0  
 Max.   :40.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt         tmax            tmin             precip    
 Min.   : 7.0   Min.   :  8.0   Min.   :-110.00   Min.   : 0.0  
 1st Qu.:11.0   1st Qu.:117.0   1st Qu.:  28.00   1st Qu.: 5.0  
 Median :11.0   Median :149.0   Median :  59.00   Median :13.0  
 Mean   :11.3   Mean   :150.3   Mean   :  60.64   Mean   :17.5  
 3rd Qu.:12.0   3rd Qu.:180.0   3rd Qu.:  92.00   3rd Qu.:27.0  
 Max.   :12.0   Max.   :305.0   Max.   : 189.00   Max.   :75.0  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.0000000   1st Qu.: 0.00000   1st Qu.:38.88   1st Qu.:-5.4981  
 Median :0.0000000   Median : 0.00000   Median :40.95   Median :-2.6938  
 Mean   :0.0006058   Mean   : 0.06597   Mean   :40.38   Mean   :-2.5144  
 3rd Qu.:0.0000000   3rd Qu.: 0.00000   3rd Qu.:41.99   3rd Qu.: 0.4914  
 Max.   :3.0000000   Max.   :77.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 200.0  
 Mean   : 352.8  
 3rd Qu.: 627.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :105.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:117.0   1st Qu.: 55.00   1st Qu.:120.0   1st Qu.:0  
 Median :10.000   Median :137.0   Median : 75.00   Median :132.5   Median :0  
 Mean   : 7.548   Mean   :141.6   Mean   : 76.25   Mean   :144.0   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:162.0   3rd Qu.: 99.00   3rd Qu.:150.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud       
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.00  
 1st Qu.:  0.000   1st Qu.:41.77   1st Qu.: -8.624   1st Qu.:  43.48  
 Median :  0.000   Median :42.43   Median : -8.411   Median : 261.00  
 Mean   :  2.336   Mean   :41.42   Mean   : -6.128   Mean   : 387.44  
 3rd Qu.:  0.000   3rd Qu.:42.89   3rd Qu.: -2.973   3rd Qu.: 370.00  
 Max.   :607.000   Max.   :43.57   Max.   :  2.827   Max.   :2400.00  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94.0   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :129.0   Median : 51.00   Median :  3.00   Median :0  
 Mean   : 6.585   Mean   :138.4   Mean   : 60.83   Mean   : 10.29   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183.0   3rd Qu.: 98.00   3rd Qu.: 13.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253.0   Max.   :159.00   Max.   :114.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1766   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip    
 Min.   :1.000   Min.   : 58.0   Min.   :-41.00   Min.   : 0.0  
 1st Qu.:2.000   1st Qu.:161.0   1st Qu.: 60.00   1st Qu.: 3.0  
 Median :3.000   Median :186.0   Median : 87.00   Median : 8.0  
 Mean   :3.173   Mean   :189.4   Mean   : 87.34   Mean   :10.7  
 3rd Qu.:4.000   3rd Qu.:218.0   3rd Qu.:115.00   3rd Qu.:16.0  
 Max.   :9.000   Max.   :321.0   Max.   :199.00   Max.   :55.0  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.000000   Min.   : 0.00000   Min.   :35.28   Min.   :-6.9492  
 1st Qu.:0.000000   1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.:-5.2892  
 Median :0.000000   Median : 0.00000   Median :38.88   Median : 0.0714  
 Mean   :0.000249   Mean   : 0.02484   Mean   :39.14   Mean   :-1.3657  
 3rd Qu.:0.000000   3rd Qu.: 0.00000   3rd Qu.:41.29   3rd Qu.: 1.1653  
 Max.   :2.000000   Max.   :40.00000   Max.   :43.49   Max.   : 4.2156  
    altitud     
 Min.   :  1.0  
 1st Qu.: 19.0  
 Median : 47.0  
 Mean   :108.7  
 3rd Qu.:143.0  
 Max.   :916.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip     
 Min.   :1.000   Min.   : -4.0   Min.   :-89.00   Min.   : 0.00  
 1st Qu.:1.000   1st Qu.:102.0   1st Qu.:  6.00   1st Qu.: 8.00  
 Median :2.000   Median :128.0   Median : 28.00   Median :17.00  
 Mean   :2.435   Mean   :127.2   Mean   : 32.26   Mean   :19.64  
 3rd Qu.:3.000   3rd Qu.:152.0   3rd Qu.: 60.00   3rd Qu.:30.00  
 Max.   :6.000   Max.   :236.0   Max.   :131.00   Max.   :80.00  
     nevada           prof_nieve          longitud        latitud      
 Min.   :0.000000   Min.   :  0.0000   Min.   :37.13   Min.   :-8.649  
 1st Qu.:0.000000   1st Qu.:  0.0000   1st Qu.:40.82   1st Qu.:-5.642  
 Median :0.000000   Median :  0.0000   Median :41.84   Median :-3.678  
 Mean   :0.001174   Mean   :  0.2518   Mean   :41.71   Mean   :-3.298  
 3rd Qu.:0.000000   3rd Qu.:  0.0000   3rd Qu.:42.85   3rd Qu.:-1.650  
 Max.   :6.000000   Max.   :229.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 251.0  
 Median : 594.0  
 Mean   : 550.3  
 3rd Qu.: 823.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 31.00   1st Qu.: -30.00   1st Qu.: 17.00  
 Median : 7.000   Median : 82.00   Median :  15.00   Median : 30.00  
 Mean   : 6.588   Mean   : 89.27   Mean   :  17.83   Mean   : 33.66  
 3rd Qu.: 9.000   3rd Qu.:144.00   3rd Qu.:  68.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :255.00   Max.   : 150.00   Max.   :126.00  
     nevada    prof_nieve         longitud        latitud           altitud    
 Min.   :0   Min.   :   0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1213  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.00   Median :42.38   Median : 0.9844   Median :2143  
 Mean   :0   Mean   :  13.38   Mean   :41.95   Mean   :-0.2329   Mean   :2107  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax          tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87   Min.   : 64.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:212   1st Qu.:150.0   1st Qu.:  0.00   1st Qu.:0  
 Median : 6.000   Median :233   Median :168.0   Median :  1.00   Median :0  
 Mean   : 6.484   Mean   :234   Mean   :169.4   Mean   :  6.22   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:259   3rd Qu.:196.0   3rd Qu.:  7.00   3rd Qu.:0  
 Max.   :12.000   Max.   :356   Max.   :244.0   Max.   :102.00   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003521   Mean   :28.38   Mean   :-15.95   Mean   :130.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 56.0   Min.   :-22.00   Min.   : 46.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:129.0   1st Qu.: 60.00   1st Qu.: 60.00   1st Qu.:0  
 Median : 5.000   Median :154.0   Median : 81.00   Median : 70.00   Median :0  
 Mean   : 6.313   Mean   :158.7   Mean   : 85.32   Mean   : 72.55   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:184.0   3rd Qu.:109.00   3rd Qu.: 83.00   3rd Qu.:0  
 Max.   :12.000   Max.   :336.0   Max.   :219.00   Max.   :119.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :28.48   Min.   :-17.755   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:41.38   1st Qu.: -8.372   1st Qu.:  27.0  
 Median : 0.00000   Median :42.89   Median : -5.346   Median :  87.0  
 Mean   : 0.08425   Mean   :41.70   Mean   : -4.681   Mean   : 159.5  
 3rd Qu.: 0.00000   3rd Qu.:43.36   3rd Qu.: -2.039   3rd Qu.: 251.0  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.216   Max.   :1405.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 4.000   Min.   :212.0   Min.   :110.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:273.0   1st Qu.:167.0   1st Qu.: 0.000   1st Qu.:0  
 Median : 8.000   Median :294.0   Median :184.0   Median : 2.000   Median :0  
 Mean   : 7.663   Mean   :295.9   Mean   :183.4   Mean   : 4.906   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:317.0   3rd Qu.:200.0   3rd Qu.: 8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :45.000   Max.   :0  
   prof_nieve    longitud        latitud           altitud     
 Min.   :0    Min.   :35.28   Min.   :-7.8603   Min.   :  1.0  
 1st Qu.:0    1st Qu.:37.42   1st Qu.:-4.4881   1st Qu.: 19.0  
 Median :0    Median :38.88   Median : 0.0714   Median : 61.0  
 Mean   :0    Mean   :39.10   Mean   :-1.2965   Mean   :119.9  
 3rd Qu.:0    3rd Qu.:41.15   3rd Qu.: 0.8192   3rd Qu.:158.0  
 Max.   :0    Max.   :43.36   Max.   : 4.2156   Max.   :717.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt         tmax            tmin             precip    
 Min.   : 7.0   Min.   :  8.0   Min.   :-110.00   Min.   : 0.0  
 1st Qu.:11.0   1st Qu.:117.0   1st Qu.:  28.00   1st Qu.: 5.0  
 Median :11.0   Median :149.0   Median :  59.00   Median :13.0  
 Mean   :11.3   Mean   :150.3   Mean   :  60.64   Mean   :17.5  
 3rd Qu.:12.0   3rd Qu.:180.0   3rd Qu.:  92.00   3rd Qu.:27.0  
 Max.   :12.0   Max.   :305.0   Max.   : 189.00   Max.   :75.0  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.0000000   1st Qu.: 0.00000   1st Qu.:38.88   1st Qu.:-5.4981  
 Median :0.0000000   Median : 0.00000   Median :40.95   Median :-2.6938  
 Mean   :0.0006058   Mean   : 0.06597   Mean   :40.38   Mean   :-2.5144  
 3rd Qu.:0.0000000   3rd Qu.: 0.00000   3rd Qu.:41.99   3rd Qu.: 0.4914  
 Max.   :3.0000000   Max.   :77.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 200.0  
 Mean   : 352.8  
 3rd Qu.: 627.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :105.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:117.0   1st Qu.: 55.00   1st Qu.:120.0   1st Qu.:0  
 Median :10.000   Median :137.0   Median : 75.00   Median :132.5   Median :0  
 Mean   : 7.548   Mean   :141.6   Mean   : 76.25   Mean   :144.0   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:162.0   3rd Qu.: 99.00   3rd Qu.:150.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud       
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.00  
 1st Qu.:  0.000   1st Qu.:41.77   1st Qu.: -8.624   1st Qu.:  43.48  
 Median :  0.000   Median :42.43   Median : -8.411   Median : 261.00  
 Mean   :  2.336   Mean   :41.42   Mean   : -6.128   Mean   : 387.44  
 3rd Qu.:  0.000   3rd Qu.:42.89   3rd Qu.: -2.973   3rd Qu.: 370.00  
 Max.   :607.000   Max.   :43.57   Max.   :  2.827   Max.   :2400.00  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax            tmin           precip         nevada 
 Min.   : 1.000   Min.   :122.0   Min.   :-31.0   Min.   : 0.0   Min.   :0  
 1st Qu.: 6.000   1st Qu.:204.0   1st Qu.: 88.0   1st Qu.: 5.0   1st Qu.:0  
 Median : 7.000   Median :235.0   Median :120.0   Median :11.0   Median :0  
 Mean   : 7.244   Mean   :238.3   Mean   :115.7   Mean   :14.5   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:273.0   3rd Qu.:145.0   3rd Qu.:21.0   3rd Qu.:0  
 Max.   :12.000   Max.   :373.0   Max.   :221.0   Max.   :84.0   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.649   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:40.47   1st Qu.:-4.767   1st Qu.: 336.0  
 Median : 0.00000   Median :41.52   Median :-3.678   Median : 617.0  
 Mean   : 0.01203   Mean   :41.40   Mean   :-3.198   Mean   : 563.1  
 3rd Qu.: 0.00000   3rd Qu.:42.56   3rd Qu.:-1.861   3rd Qu.: 788.0  
 Max.   :40.00000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAyNjYKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkCiogRGltZW5zaW9uZXMgZGVsIG1hcGE6IDUsNQoqIEl0ZXJhY2lvbmVzOiAxMDAwMAoqIFBhcsOhbWV0cm9zIGFkaWNpb25hbGVzOiAKCmBgYHtyfQpzb3VyY2UoIi4uLy4uL2xpYi9zb20tdXRpbHMuUiIpCnNvdXJjZSgiLi4vLi4vbGliL21hcHMtdXRpbHMuUiIpCmBgYAoKIyBDYXJnYSBkZWwgbW9kZWxvIGRlc2RlIGRpc2NvCgpgYGB7cn0KbXByLnNldF9iYXNlX3BhdGhfYW5hbHlzaXMoKQptb2RlbCA8LSBtcHIubG9hZF9tb2RlbCgic29tLTI2Ni5yZHMueHoiKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjaGFuZ2VzIikKYGBgCgojIENhcmdhIGRlbCBkYXRhc2V0IGRlIGVudHJhZGEKCmBgYHtyfQpkZiA8LSBtcHIubG9hZF9kYXRhKCJkYXRvc19tZXMuY3N2Lnh6IikKYGBgCgpgYGB7cn0KZGYKYGBgCgpgYGB7cn0Kc3VtbWFyeShkZikKYGBgCgojIENhcmdhIGRlIGxvcyBtYXBhcwoKYGBge3J9CndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCnNwYWluIDwtIHN1YnNldCh3b3JsZCwgYWRtaW4gPT0gIlNwYWluIikKYGBgCgojIE1hcGEgZGUgZGVuc2lkYWQKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjb3VudCIsIHNoYXBlID0gInN0cmFpZ2h0IiwgcGFsZXR0ZS5uYW1lID0gbXByLmRlZ3JhZGUuYmxldSkKYGBgCgpOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNlbGRhOgoKYGBge3J9Cm5iIDwtIHRhYmxlKG1vZGVsJHVuaXQuY2xhc3NpZikKcHJpbnQobmIpCmBgYApDb21wcm9iYWNpw7NuIGRlIG5vZG9zIHZhY8Otb3M6CgpgYGB7cn0KZGltX21vZGVsIDwtIDUqNTsKbGVuX25iID0gbGVuZ3RoKG5iKTsKZW1wdHlfbm9kZXMgPC0gZGltX21vZGVsICE9IGxlbl9uYjsKaWYgKGVtcHR5X25vZGVzKSB7CiAgcHJpbnQocGFzdGUoIltXYXJuaW5nXSBFeGlzdGVuIG5vZG9zIHZhY8Otb3M6ICIsIGxlbl9uYiwgIi8iLCBkaW1fbW9kZWwpKQp9CmBgYAoKIyBNYXBhIGRlIGRpc3RhbmNpYSBlbnRyZSB2ZWNpbm9zCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iZGlzdC5uZWlnaGJvdXJzIiwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMgSW5mbHVlbmNpYSBkZSBsYXMgdmFyaWFibGVzCgpgYGB7cn0KbW9kZWxfY29sbmFtZXMgPSBjKCJmZWNoYV9jbnQiLCAidG1heCIsICJ0bWluIiwgInByZWNpcCIsICJsb25naXR1ZCIsICJsYXRpdHVkIiwgImFsdGl0dWQiKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK